/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.CrossValidation;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import main.KBProcess.Element;
import main.NER.Trie.NER_Candidate;
import main.Weighting.EvaluationParams;
import main.initiate.UTEES_Index;

/**
 *
 * @author Isaac Osesina
 */
public class CandidateGroupings implements Serializable, Cloneable{

    private List<Element> entityList;
    private HashMap<String, Integer> countByETypeKB;

    public CandidateGroupings(List<Element> entityList) {
        this.entityList = entityList;
        countByEType();
    }


    public static HashMap<String, Integer> putInMap_Increment(HashMap<String, Integer> inMap, String str, Integer inNum) {
        Integer freq = inMap.get(str);
        if(freq!=null) {
            freq += inNum;
        }
        else {
            freq = 1;
        }
        inMap.put(str, freq);
        return inMap;
    }

    public final void countByEType() {
        countByETypeKB = new HashMap<String, Integer>();
        for(Element entity:entityList) {
            Integer freq = countByETypeKB.get(entity.getLabel());
            putInMap_Increment(countByETypeKB, entity.getLabel(), freq);
        }
    }

    public HashMap<String, Integer> countCandidatesByEType(List<NER_Candidate> candidates) {
        HashMap<String, Integer> countCorrectCandidatesByEType = new HashMap<String, Integer>();
        for(NER_Candidate cand:candidates) {
            countCorrectCandidatesByEType = putInMap_Increment(countCorrectCandidatesByEType, cand.getEntityName(), 1);
        }
        return countCorrectCandidatesByEType;
    }

    public HashMap<String, Integer> countCorrectCandidatesByEType(List<NER_Candidate> candidates) {
        HashMap<String, Integer> countCorrectCandidatesByEType = new HashMap<String, Integer>();
        for(NER_Candidate cand:candidates) {
            if( isCandidateCorrect(cand) ) {
                cand.markAsCorrect();
                countCorrectCandidatesByEType = putInMap_Increment(countCorrectCandidatesByEType, cand.getEntityName(), 1);
            }
        }
        return countCorrectCandidatesByEType;
    }

    public boolean isCandidateCorrect(NER_Candidate candidate) {
        String doublePad = UTEES_Index.PADChar + "" + UTEES_Index.PADChar;
        for(Element entity:entityList) {
            if( entity.getLabel().compareTo(candidate.getEntityName())==0 &&
                entity.getIndexOf() ==candidate.getStartPos()-doublePad.length() &&
                entity.getValue().compareTo(candidate.getEntityValue())==0 )
                return true;
        }
        return false;
    }

    public HashMap<String, EvaluationParams> evaluatePerformanceByEType(List<NER_Candidate> candidates) {

        HashMap<String, EvaluationParams> weightMethodEvalParamByEType = new HashMap<String, EvaluationParams>();
        HashMap<String, Integer> countCorrectCandidatesByEType = countCorrectCandidatesByEType(candidates);
        HashMap<String, Integer> countCandidatesByEType = countCandidatesByEType(candidates);
        for(String eName:countCandidatesByEType.keySet()) {
            double totalPossibleCount = countByETypeKB.get(eName);
            double totalCandCount = countCandidatesByEType.get(eName);
            Integer correctCandCount = countCorrectCandidatesByEType.get(eName);
            if(correctCandCount==null) {
               correctCandCount = 0;
            }
            double precision = 0;
            double recall = 0;
            if(totalPossibleCount > 0) {
                precision = (double)correctCandCount/totalPossibleCount;
            }
            if(totalCandCount > 0) {
                recall = (double)correctCandCount/totalCandCount;
            }
            EvaluationParams eValParam = new EvaluationParams(precision, recall);
            weightMethodEvalParamByEType.put(eName, eValParam);
        }
        return weightMethodEvalParamByEType;
    }

    public EvaluationParams evaluatePerformance(ArrayList<NER_Candidate> candidates) {
        HashMap<String, EvaluationParams> evaluatePerformanceByEType = evaluatePerformanceByEType(candidates);
        double totPrecision = 0;
        double totalRecall = 0;
        int count = 0;
        for(Entry<String, EvaluationParams> entry:evaluatePerformanceByEType.entrySet()) {
            totPrecision += entry.getValue().getPrecision();
            totalRecall += entry.getValue().getRecall();
            count++;
        }
        if(count!=0) {
            return new EvaluationParams(totPrecision/count, totalRecall/count);
        }
        else {
            return new EvaluationParams(0, 0);
        }
    }

}
